# fable_library/core/options.pyi
from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

from .array import FSharpArray as Array

_T = TypeVar("_T")
_U = TypeVar("_U")
_V = TypeVar("_V")
_W = TypeVar("_W")  # For map3 result

class SomeWrapper(Generic[_T]):
    value: _T
    def __init__(self, value: _T) -> None: ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...

# Type alias for Option based on SomeWrapper or None
type Option[_T] = SomeWrapper[_T] | _T | None

def default_arg(opt: Option[_T], default_value: _T) -> _T: ...
def default_arg_with(opt: Option[_T], def_thunk: Callable[[], _T]) -> _T: ...
def filter(predicate: Callable[[_T], bool], opt: Option[_T]) -> Option[_T]: ...
def map(mapping: Callable[[_T], _U], opt: Option[_T]) -> Option[_U]: ...
def map2(mapping: Callable[[_T, _U], _V], opt1: Option[_T], opt2: Option[_U]) -> Option[_V]: ...
def map3(mapping: Callable[[_T, _U, _V], _W], opt1: Option[_T], opt2: Option[_U], opt3: Option[_V]) -> Option[_W]: ...

# Based on Rust implementation's behavior with SomeWrapper
def some(x: _T) -> SomeWrapper[_T]: ...
def value(x: Option[_T] | _T) -> _T: ...  # Raises ValueError if None

# Converts Python Optional[T] (T | None) to F# Option[T] (Some T | None)
def of_nullable(x: _T | None) -> Option[_T]: ...

# Converts F# Option<T> to Python Optional[T] (Some T -> T, None -> None)
def to_nullable(x: Option[_T]) -> _T | None: ...
def flatten(x: Option[Option[_T]]) -> Option[_T]: ...
def to_array(opt: Option[_T]) -> Array[_T]: ...
def bind(binder: Callable[[_T], Option[_U]], opt: Option[_T]) -> Option[_U]: ...
def or_else(opt: Option[_T], if_none: Option[_T]) -> Option[_T]: ...
def or_else_with(opt: Option[_T], if_none_thunk: Callable[[], Option[_T]]) -> Option[_T]: ...

# For nullable reference types - returns value if not None, raises ValueError if None
def non_null(x: _T | None) -> _T: ...
